<?php

class PlistParser {
    private $data;

    public function __construct($data) {
        // 清理XML声明和换行符（保留原始结构）
        $this->data = preg_replace('/<\?xml.*?\?>\s*/', '', $data);
        $this->data = preg_replace('/<!DOCTYPE.*?>\s*/', '', $this->data);
        $this->data = str_replace(["\r", "\n"], ' ', $this->data); // 替换换行为空格
        $this->data = preg_replace('/\s+/', ' ', $this->data);     // 压缩连续空格
    }

    private function parseElement(&$xml) {
        $xml = trim($xml);
        if (empty($xml)) return null;

        // 优先处理 <key>
        if (preg_match('/^<key>(.*?)<\/key>(.*)/s', $xml, $keyMatch)) {
            $key = $keyMatch[1];
            $remaining = $keyMatch[2];
            $value = $this->parseValueNode($remaining, $remaining);
            $xml = $remaining;
            return [$key => $value];
        }

        // 处理数组元素
        if (preg_match('/^<(string|integer|true|false|dict|array)>(.*)/s', $xml, $typeMatch)) {
            $value = $this->parseValueNode($typeMatch[0], $xml);
            return $value;
        }

        return null;
    }

    private function parseValueNode($str, &$remaining) {
        $str = trim($str);
        
        // 处理布尔值
        if (preg_match('/^<true\/>(.*)/s', $str, $match)) {
            $remaining = $match[1];
            return true;
        }
        if (preg_match('/^<false\/>(.*)/s', $str, $match)) {
            $remaining = $match[1];
            return false;
        }

        // 处理基础类型
        if (preg_match('/^<(string|integer)>(.*?)<\/\1>(.*)/s', $str, $match)) {
            $remaining = $match[3];
            return $this->parsePrimitive($match[1], $match[2]);
        }

        // 处理字典
        if (preg_match('/^<dict>(.*)<\/dict>(.*)/s', $str, $match)) {
            $content = $match[1];
            $remaining = $match[2];
            return $this->parseDict($content);
        }

        // 处理数组
        if (preg_match('/^<array>(.*)<\/array>(.*)/s', $str, $match)) {
            $content = $match[1];
            $remaining = $match[2];
            return $this->parseArray($content);
        }

        return null;
    }

    private function parsePrimitive($type, $value) {
        switch ($type) {
            case 'string':
                return preg_replace('/<!\[CDATA\[(.*?)\]\]>/', '$1', $value);
            case 'integer':
                return intval($value);
            default:
                return $value;
        }
    }

    private function parseDict($xml) {
        $result = [];
        while ($parsed = $this->parseElement($xml)) {
            $result = array_merge($result, $parsed);
        }
        return $result;
    }

    private function parseArray($xml) {
        $result = [];
        while (true) {
            $element = $this->parseValueNode($xml, $xml);
            if ($element === null) break;
            $result[] = $element;
        }
        return $result;
    }

    public function parse() {
        // 匹配根plist内容
        if (preg_match('/<plist[^>]*>(.*)<\/plist>/s', $this->data, $plistMatch)) {
            $content = trim($plistMatch[1]);
            // 匹配根字典
            if (preg_match('/<dict>(.*)<\/dict>/s', $content, $dictMatch)) {
                return $this->parseDict($dictMatch[1]);
            }
        }
        return [];
    }
}